<template>
    <svg id="graph" ref="queryBoard"></svg>
  </template>
  
    
    <script>
    import {mapActions} from 'vuex'
    import {deepCopy} from '../../../common/utils/object'
    import {consoleGroup} from '../../../common/utils/message'
    import config from '../../graph/utils/config'
    import {getGridLayout, calcScale} from '../../graph/utils/layout'
    import GraphEditorItem from "../../../modules/graph/components/GraphEditorItem";
    import bus from "../../graph/utils/eventBus";
    
  //   import GraphEditorGroup from "./GraphEditorGroup";
    
    
    export default {
    
    
      components: {
        GraphEditorItem
      },
    
      name: 'GraphQueryBoard',
      props: {
        data: {
          type: Object
        },
  
      },
      data() {
        return {
          origin: null,
          config: {...config},
          projectInfo: null,
          projectId: 0,
          layouts: null,
          layoutMode: 'FORCE',
          s: [],
    
          //wx
          colorJudge: [],
          forNumber: 1,
          middleLinks: [],
          allNodes: [],
          hasDoubleClicked: [],
    
          links: [],
          delenodes: [],
          delelinks: [],
          focusNodes: [],
          selectedGroups: [],
          svgElements: {
            simulation: null,
            svg: null,
            defs: null,
            marker: null,
            view: null,
            root: null,
            focusGroup: null,
    
            //wx
            focusGroup_wx: null,
    
            svgLinks: null,
            svgLinksText: null,
            svgNodes: null,
            svgNodesText: null,
            svgMenuText: null,
            boundDrag: null,
            boundZoom: null,
            scale: null
          },
          flags: {
            loaded: false,
            singleFocus: true,
            enableFocus: true,
            pinned: false,
            locked: false,
            selectingMode: false
          },
          graphData: null,
          selectedItem: {
            type: null,
            item: {}
          },
          
        }
      },
    
      methods: {
    
        // ...mapActions(['updateLayout', 'saveAsPng', 'saveAsXml']),
    
        //wx
        ...mapActions({
          createItemAct: 'createItem',
          updateItemAct: 'updateItem',
          deleteItemNodeAct: 'deleteItemNode',
          // showMore: 'showMore',
          updateLayout: 'updateLayout',
          saveAsPng: 'saveAsPng',
          saveAsXml: 'saveAsXml',
          entityQueryGlobal:'entityQueryGlobal',
          getProjectInfoAct: 'getProjectInfo',
        }),
        /***** 重新挂载图谱 *****/
        mountGraphData(data) {
          // console.log('projectInfo:', this.projectId)
          console.log('daataaaaa'+data)
          this.origin = deepCopy(data)
          // this.projectInfo = this.getProjectInfoAct(this.projectId)
          const {nodes, links, layouts} = data
          this.nodes = [...nodes]
          console.log("项目所有节点849561：" + JSON.stringify(this.nodes))
          this.links = [...links]
          this.layouts = deepCopy(layouts)
    
          // console.log("布局验证：" + JSON.stringify(this.layouts))
    
          // consoleGroup('mountGraphData', () => {
          //   console.log('nodes:', this.nodes)
          //   console.log('links:', this.links)
          //   console.log('layouts:', this.layouts)
          // })
    
          this.init()
          this.flags.loaded = true
        },
        /***** 图谱绘制 *****/
        // 初始化图谱
        init() {
          const {
            // 全局变量 & 配置
            $d3,
            $el,
            config: {width, height},
            // 子例程
            reset,
            setSimulation,
            setView,
            setRoot,
            setFocusGroup,
            setLinks,
            setLinksText,
            setNodes,
            setNodesText,
            setMenuCircle,
            // 力导图绑定事件
            setDrag,
            setZoom,
            tick,
            // 图谱操作
            resetZoom,
            setEnableFocus,
            restoreLayout,
    
          } = this
          // 清除图谱
          reset()
          setEnableFocus(false)
    
          this.middleLinks = this.links
    
          const simulation = setSimulation()
    
          const svg = $d3
            .select($el)
            .attr('viewBox', [-width / 2, -height / 2, width, height])
          this.svgElements.svg = svg
    
          // 设置 defs 定义组
          // setDefs(svg)
    
          // 设置透明操作板
          const view = setView(svg)
          const root = setRoot(svg)
    
          // const g =  svg.append('g')
          //   .attr('transform', 'translate(' + marge.top + ',' + marge.left + ')')
          //   .attr('class', 'container')
          // this.linksText = g.append('g')
          //   .selectAll('text')
          //   .data(edges)
          //   .enter()
          //   .append('text')
          //   .attr('class', 'linksText')
          //   .text(function (d) {
          //     return d.relations
          //   })
          //   .style('font-size', 14)
          //   .attr('fill-opacity', 0)
    
          const boundZoom = setZoom(root)
          view.call(boundZoom)
    
          // 设置组
          setFocusGroup(root)
    
          // 设置关系、关系文字
          setLinks(root)
          setLinksText(root)
    
    
          const boundDrag = setDrag(simulation)
          const scale = $d3.scaleOrdinal($d3.schemeCategory10)
          this.svgElements.scale = scale
          this.$emit('init-property', 'nodeScale', scale)
          //设置图片
          // drawPattern(root)
          // 设置节点、节点文字
          setNodes(root, boundDrag, scale)
          setNodesText(root, boundDrag)
    
          //设置环形菜单
          setMenuCircle(root)
    
          simulation.on('tick', tick)
    
          // setTimeout(() => {
          //   resetZoom()
          // }, 300)
          setTimeout(() => {
            resetZoom()
          }, 600)
          setEnableFocus(true)
          restoreLayout()
        },
        // 重置图谱节点
        reset() {
          const {view, root} = this.svgElements
          if (view) view.remove()
          if (root) root.remove()
        },
        // 设置力导图初始化
        setSimulation() {
          const {
            $d3,
            nodes,
            links,
            config: {baseRadius}
          } = this
          const simulation = $d3
            .forceSimulation(nodes)
            .force(
              'link',
              $d3
                .forceLink(links)
                .id(d => d.id)
                .distance(
                  d => (d.source.radius + d.target.radius) * 30 + baseRadius
                )
            )
            .force(
              'charge',
              $d3.forceManyBody().strength(d => -1000 - d.radius * 300)
            )
            .force('x', $d3.forceX())
            .force('y', $d3.forceY())
          this.svgElements.simulation = simulation
          return simulation
        },
        setDefs(svg) {
          const defs = this.svgElements.defs || svg.append('defs')
          this.svgElements.defs = defs
          return defs
        },
        // 设置拖曳背景图
        setView(svg) {
          const {width, height} = this.config
          const view = svg
            .append('rect')
            .attr('class', 'view')
            .style('fill', 'transparent')
            .attr('x', -width / 2)
            .attr('y', -height / 2)
            .attr('width', width)
            .attr('height', height)
            .on('click', this.clickView)
          this.svgElements.view = view
          return view
        },
        // 设置图谱根节点
        setRoot(svg) {
          const root = svg.append('g').attr('class', 'root')
          this.svgElements.root = root
          return root
        },
    
    
        // 设置图谱高亮组
        setFocusGroup(root) {
          const focusGroup = root
            .append('g')
            .attr('class', 'focus')
            .attr('stroke', 'skyblue')
            .attr('stroke-width', 20)
          this.svgElements.focusGroup = focusGroup
        },
    
        //设置环形菜单
        setMenuCircle(root) {
          const svgMenuText = root
            .append('g')
            .attr('class', 'Circle')
          this.svgElements.svgMenuText = svgMenuText
        },
        setLinks(root) {
          const {links, clickLink, $d3} = this
    
          // console.log("root打印：" + JSON.stringify(root))
    
          //修改箭头位置
          const arrowMarker = root
            .append('g')
            .append("defs")
            .append("marker")
            .attr("id", "arrow")
            .attr("viewBox", "0 -5 10 10")//坐标系的区域
            // .selectAll('line')
            // .data(links)
            // .join('line')
            // .attr("refX",function (d) { 
            //   if(d.radius){
            //     console.log("dddd"+d.radius)
            //   var res = 40 + (d.radius - 5)* 8.5
            //  console.log("dddd"+res)
            //   return res
            //   }else{
            //     console.log("不知道半径"+d.radius)
            //     return 74
            //   } 
            //   })
        // 1,40 3，57  4，65，5，74
            .attr("refX", 74)//箭头坐标
            
            .attr("refY", 0)
            .attr("markerWidth", 12)//标识的大小
            .attr("markerHeight", 12)
            // .attr("markerUnits", "strokeWidth")
            // .attr("markerWidth", "5")
            // .attr("markerHeight", "5")
            // .attr("viewBox", "0 0 12 12")
            // .attr("refX", 69)
            // .attr("refY", "6")
  
            
            .attr("orient", "auto");
    
          const arrow_path = "M0,-5L10,0L0,5";
          // const arrow_path = "M2,2 L10,6 L2,10 L6,6 L2,2";
          arrowMarker.append("path")
            .attr("d", arrow_path)
            .attr("fill", "#999 ");
    
    
          // 设置关系线段
          const svgLinks = root
            .append('g')
            .attr('class', 'links')
            .attr('stroke', '#999')
            .attr('stroke-opacity', 1)
            .selectAll('line')
            .data(links)
            .join('line')
            .attr('stroke-width', d => d.value )
            .attr('id', d => `link-${d.id}`)
            .attr('data-id', d => d.id)
            // .attr('marker-end', d => `url(#arrow-${d.id})`)
            .attr("marker-end", "url(#arrow)")
            .attr("arrowValue", d => d.value)
            .on('click', clickLink)
          svgLinks.append('title').text(d => d.name)
          // arrowMarker.attr("refX", svgLinks.attr("a"));
          this.svgElements.svgLinks = svgLinks
          return svgLinks
        },
        setLinksText(root) {
          const {
            config: {font, fontSize},
            setLinksPositionRaio,
            links,
            clickLink
          } = this
          const svgLinksText = root
            .append('g')
            .attr('class', 'links_text')
            .selectAll('text')
            .data(links)
            .join('text')
            .style('fill', '#ffffff')
            .style('font', `${fontSize}px ${font}`)
            .style('user-select', 'none')
            .attr('dominant-baseline', 'middle')
            .attr('text-anchor', 'middle')
            .attr('data-id', d => d.id)
            .text(d => d.name)
            .on('click', clickLink)
          this.svgElements.svgLinksText = svgLinksText
    
          setLinksPositionRaio()
    
          return svgLinksText
        },
    
        // 绘制图片
        drawPattern() {
          console.log("执行了背景设置方法")
          const {
            config: {baseRadius},
            nodes,
            focus,
            unfocus,
            clickNode,
            root
          } = this
    
          let gPattern = root.append("g").attr("class", "g-pattern");
    
          //  添加pattern
          var pattern = gPattern.selectAll("pattern").data(nodes, function (d) {
            return "pattern" + d.id;
          });
    
          // 赋予宽高
          pattern
            .enter()
            .append("pattern")
            .attr("id", function (d) {
              return "pattern" + d.id;
            })
            .attr("x", 0)
            .attr("y", 0)
            .attr("height", function (d) {
              var imageHeight;
              // if (d.group === "态势") {
              if (d.group === "一级分类") {
                imageHeight = 78;
              } else if (d.group === "参与方") {
                imageHeight = 60;
              } else if (d.group === "作战单元") {
                imageHeight = 45;
              } else {
                imageHeight = 55;
              }
              return imageHeight
            })
            .attr("width", function (d) {
              var imageWidth;
              // if (d.group === "态势") {
              if (d.group === "一级分类") {
                imageWidth = 78;
              } else if (d.group === "参与方") {
                imageWidth = 60;
              } else if (d.group === "作战单元") {
                imageWidth = 45;
              } else {
                imageWidth = 55;
              }
              return imageWidth
            })
            .append("image")
            .attr("preserveAspectRatio", "none")
            .attr("xlink:href", function (d) {
              console.log("imagePath2555:" + d.group)
              var imagePath = "";
              // if (d.group === "态势") {
              if (d.group === "一级分类") {
                imagePath = require("@/assets/tsh.png");
              } else if (d.group === "参与方") {
                imagePath = require("@/assets/cyf.png");
              } else if (d.group === "作战单元") {
                imagePath = require("@/assets/jc.png");
              } else {
                imagePath = require("@/assets/airfw.png");
              }
              return imagePath
            })
            .attr("x", 0)
            .attr("y", 0)
            .attr("height", function (d) {
              return (baseRadius + d.radius * 10) * 2;
            })
            .attr("width", function (d) {
              return (baseRadius + d.radius * 10) * 2
            });
        },
        setNodes(root, boundDrag, scale) {
          const {
            config: {baseRadius},
            nodes,
            focus,
            unfocus,
            clickNode,
            doubleClick,
            drawPattern,
            rightClickNode
          } = this
    
          nodes.filter(node => {
            node.isDelete = false
            node.isNew = false
            // console.log("456测试wx：" + JSON.stringify(node))
          })
    
          const svgNodes = root
            .append('g')
            .attr('class', 'nodes')
            .attr('stroke', '#ffffff')
            .attr('stroke-width', 1.5)
            .selectAll('circle')
            .data(nodes)
            .join('circle')
            .attr('r', d => baseRadius + d.radius * 10)
            .attr('fill', d => (d.color ? d.color : scale(d.group)))
            //.style('fill',function(d){ return "url(#" + "pattern" + d.id + ")"; })
            .attr('data-id', d => d.id)
            .call(boundDrag)
            .on('click', clickNode)
            .on('contextmenu', rightClickNode)
            .on('mouseover', focus)
            .on('mouseout', unfocus)
            .on('dblclick', doubleClick)
          svgNodes.append('title').text(d => d.name)
          this.svgElements.svgNodes = svgNodes
          return svgNodes
        },
        setNodesText(root, boundDrag) {
          const {
            $d3,
            config: {font},
            nodes,
            clickNode,
            focus,
            unfocus,
            doubleClick,
            rightClickNode,
          } = this
          const svgNodesText = root
            .append('g')
            .attr('class', 'nodes_text')
            .selectAll('text')
            .data(nodes)
            .join('text')
            .style('fill', '#ffffff')
            .style('font', d => `${d.textSize}px ${font}`)
            .style('user-select', 'none')
            .attr('dominant-baseline', 'middle')
            .attr('text-anchor', 'middle')
            .attr('data-id', d => d.id)
            .text(d => d.name)
            .call(boundDrag)
            .on('click', clickNode)
            .on('contextmenu', rightClickNode)
            .on('dblclick', doubleClick)
            .on('mouseover', focus)
            .on('mouseout', unfocus)
          this.svgElements.svgNodesText = svgNodesText
    
          // console.log("493调试：" + JSON.stringify($d3.selectAll('root').size()))
    
          return svgNodesText
        },
        // 设置 focus 节点
        setFocus(node) {
          const {
            svgElements: {focusGroup: fg},
            flags: {enableFocus},
            setNodeHighLight,
            updateHighLightNodes
          } = this
          this.clearFocus()
          if (!enableFocus) return
    
          if (fg.select(`#focus-node-${node.id}`).empty()) {
            setNodeHighLight(node, true)
            updateHighLightNodes()
          }
        },
        updateHighLightNodes() {
          const {
            config: {baseRadius},
            nodes,
            svgElements: {focusGroup: fg}
          } = this
    
          const originFocus = fg.selectAll('circle')
          fg.selectAll('circle')
            .data(nodes.filter(node => node.highLight || node.focus))
            .join('circle')
            .attr('r', d => baseRadius + d.radius * 10 + 5)
            .attr('fill', 'none')
            .attr('id', d => `focus-node-${d.id}`)
            .attr('cx', d => d.x)
            .attr('cy', d => d.y)
            .merge(originFocus)
        },
        // 力导图更新
        tick() {
          const {
            focusGroup,
            svgLinks,
            svgLinksText,
            svgNodes,
            svgNodesText,
            svgMenuText
          } = this.svgElements
    
          svgLinks
            .attr('x1', d => d.source.x)
            .attr('y1', d => d.source.y)
            .attr('x2', d => d.target.x)
            .attr('y2', d => d.target.y)
    
          svgLinksText
            .attr('x', d => {
              const {
                source: {x: x1},
                target: {x: x2},
                positionRatio
              } = d
              return x1 + (x2 - x1) * positionRatio
            })
            .attr('y', d => {
              const {
                source: {y: y1},
                target: {y: y2},
                positionRatio
              } = d
              return y1 + (y2 - y1) * positionRatio
            })
    
          svgNodes.attr('cx', d => d.x).attr('cy', d => d.y)
          svgNodesText.attr('x', d => d.x).attr('y', d => d.y)
    
          focusGroup
            .selectAll('circle')
            .attr('cx', d => d.x)
            .attr('cy', d => d.y)
    
          svgMenuText
            .select('menuCircle')
            .attr("transform", function (d) {
              var x1 = d.x
              var y1 = d.y
              return 'translate(' + x1 + ',' + y1 + ')';
            })
          
        },
    
    
        updateNodesWithText() {
          if (!this.flags.loaded) return
          const {
            $d3,
            config: {baseRadius, font, opacity},
            nodes,
            links,
            doubleClick,
            svgElements: {
              simulation,
              root,
              svgNodes,
              svgNodesText,
              boundDrag,
              scale
            },
            clickNode,
            focus,
            unfocus,
            updateAllOpacity,
            drawPattern,
            rightClickNode
          } = this
          // console.log('updateNodesWithText', nodes)
          updateAllOpacity()
    
          // console.log("节点更新测试222："+JSON.stringify(nodes))
    
          // update nodes
          //修改节点背景
          let _svgNodes = root
            .select('g.nodes')
            .selectAll('circle')
            .data(nodes)
            .join('circle')
            .attr('r', d => baseRadius + d.radius * 10)
            .attr('fill', d => (d.color ? d.color : scale(d.group)))
            // .attr('fill',"red")
            //.style('fill',function(d){ return "url(#" + "pattern" + d.id + ")"; })
            .attr('opacity', d => (d.opacity ))
            .attr('data-id', d => d.id)
            .attr('cx', d => d.x)
            .attr('cy', d => d.y)
            .call(boundDrag)
            .on('click', clickNode)
            .on('contextmenu', rightClickNode)
            .on('dblclick', doubleClick)
            .on('mouseover', focus)
            .on('mouseout', unfocus)
    
          _svgNodes.append('title').text(d => d.name)
          _svgNodes = _svgNodes.merge(svgNodes)
          this.svgElements.svgNodes = _svgNodes
    
          // update nodes text
          const _svgNodesText = root
            .select('g.nodes_text')
            .selectAll('text')
            .data(nodes)
            .join('text')
            .style('fill', d => (d.isDelete ? '#ffffff33' : '#ffffff'))
            .style('font', d => `${d.textSize}px ${font}`)
            .style('user-select', 'none')
            .attr('dominant-baseline', 'middle')
            .attr('text-anchor', 'middle')
            .attr('data-id', d => d.id)
            .text(d => d.name)
            .call(boundDrag)
            .on('click', clickNode)
            .on('contextmenu', rightClickNode)
            .on('dblclick', doubleClick)
            .on('mouseover', focus)
            .on('mouseout', unfocus)
            .merge(svgNodesText)
          this.svgElements.svgNodesText = _svgNodesText
    
          // console.log("652测试：" + JSON.stringify(_svgNodesText.selectAll('text')))
          // console.log("nodes处理结果qfvsd："+JSON.stringify(nodes))
    
          bus.$emit("updataSearchNodes", nodes)
          // console.log("搜索传输节点（发）："+JSON.stringify(nodes))
    
    
          simulation.nodes(nodes)
          simulation.force('link').links(links)
          simulation.alpha(1).restart()
        },
        updateLinksWithText() {
          if (!this.flags.loaded) return
          const {
            config: {fontSize, font, opacity},
            nodes,
            links,
            svgElements: {simulation, root, svgLinks, svgLinksText},
            setLinksPositionRaio,
            clickLink,
            drawPattern,
            updateAllOpacity
          } = this
          // console.log('updateLinksWithText', links)
          updateAllOpacity()
    
          // console.log("关系初始化25225："+JSON.stringify(links))
    
          // update links
          let _svgLinks = root
            .select('g.links')
            .selectAll('line')
            .data(links)
            .join('line')
            .attr('stroke-width', d => d.value)
            .attr('opacity', d => (d.opacity ))
            .attr('id', d => `link-${d.id}`)
            .attr('data-id', d => d.id)
            // .attr('marker-end', d => `url(#arrow-${d.id})`)
            .attr('marker-end', d => `url(#arrow)`)
            .on('click', clickLink)
          _svgLinks.append('title').text(d => d.name)
          _svgLinks = _svgLinks.merge(svgLinks)
          this.svgElements.svgLinks = _svgLinks
    
          // update links text
          const _svgLinksText = root
            .select('g.links_text')
            .selectAll('text')
            .data(links)
            .join('text')
            .style('fill', '#ffffff')
            .style('font', `${fontSize}px ${font}`)
            .attr('opacity', d => (d.opacity ))
            .style('user-select', 'none')
            .attr('dominant-baseline', 'middle')
            .attr('text-anchor', 'middle')
            .attr('data-id', d => d.id)
            // .text(d => d.name)
            .on('click', clickLink)
            .merge(svgLinksText)
          this.svgElements.svgLinksText = _svgLinksText
          simulation.nodes(nodes)
          simulation.force('link').links(links)
          simulation.alpha(1).restart()
          setLinksPositionRaio()
        },
        setLinksPositionRaio() {
          const {
            config: {baseRadius},
            links
          } = this
          links.forEach(link => {
            const {
              source: {radius: r1},
              target: {radius: r2}
            } = link
            link.positionRatio = (baseRadius + r1 * 20) / ((r1 + r2) * 30 + baseRadius)
          })
        },
        updateFocus() {
          const {
            config: {baseRadius},
            svgElements: {focusGroup: fg}
          } = this
          const originFocus = fg.selectAll('circle')
          fg.selectAll('circle')
            .data(this.nodes.filter(node => node.highLight || node.focus))
            .join('circle')
            .attr('r', d => baseRadius + d.radius * 10 + 5)
            .attr('fill', 'none')
            .attr('id', d => `focus-node-${d.id}`)
            .attr('cx', d => d.x)
            .attr('cy', d => d.y)
            .merge(originFocus)
        },
        /********** 外部节点操作 **********/
        createNode(node) {
          // console.log('[GraphBoard] createNode', node)
          const {
            nodes,
            updateNodesWithText,
            setNodeFocus,
            setFocus,
            layoutMode,
            restoreLayout
          } = this
          nodes.push(node)
          updateNodesWithText()
          setNodeFocus(node)
          setFocus(node)
          layoutMode === 'GRID' && restoreLayout(true)
        },
        createLink(link) {
    
          // console.log('[GraphBoard] createLink', link)
          const {links, updateLinksWithText} = this
          links.push(link)
          updateLinksWithText()
        },
        updateNode(node) {
          // console.log('[GraphBoard]', node)
          const {
            nodes,
            updateNodesWithText,
            setNodeFocus,
            updateFocus,
            layoutMode,
            restoreLayout
          } = this
          const _node = nodes.filter(_node => _node.id === node.id)[0]
          for (const prop in _node) {
            _node[prop] = node[prop]
          }
          updateNodesWithText()
          setNodeFocus(_node)
          updateFocus()
          layoutMode === 'GRID' && restoreLayout(true)
        },
        updateLink(link) {
          // console.log('[GraphBoard]', link)
          const _link = this.links.filter(_link => _link.id === link.id)[0]
          for (const prop in _link) {
            link[prop] = link[prop]
          }
          this.updateLinksWithText()
        },
        deleteNode(nodeId) {
          // console.log('[GraphBoard]', nodeId)
          const {
            nodes,
            links,
            updateNodesWithText,
            updateLinksWithText,
            clearFocus,
            layoutMode,
            restoreLayout
          } = this
          // delete node
          const node = nodes.filter(node => node.id === nodeId)[0]
          nodes.splice(nodes.indexOf(node), 1)
    
          // delenodes
          const _link = links.filter(_link => _link.to === node.id || _link.from === node.id)
          for (const prop in _link) {
            this.delelinks.push(_link[prop])
          }
          // delete links
          this.links = links.filter(
            ({from, to}) => from !== node.id && to !== node.id
          )
          updateNodesWithText()
          updateLinksWithText()
          clearFocus()
          layoutMode === 'GRID' && restoreLayout(true)
        },
        deleteLink(linkId) {
          // console.log('[GraphBoard]', linkId)
          const {links} = this
          const link = links.filter(link => link.id === linkId)[0]
          links.splice(links.indexOf(link), 1)
          this.updateLinksWithText()
        },
        updateData() {
          this.updateNodesWithText()
          this.updateLinksWithText()
        },
        /********** 外部图谱操作 **********/
        // 重置缩放
        resetZoom() {
          const {
            $d3,
            config,
            nodes,
            svgElements: {view, boundZoom}
          } = this
          const scale = calcScale(nodes, config)
          view
            .transition()
            .duration(750)
            .call(boundZoom.transform, $d3.zoomIdentity.scale(scale))
        },
        // 随机分布
        randomDisorder() {
          const {
            svgElements: {simulation}
          } = this
          if (this.layoutMode === 'FORCE') {
            this.nodes.forEach(node => {
              node.vx = node.vy = null
              node.x = node.y = null
              node.fx = node.fy = null
            })
            simulation.alphaTarget(0.3).restart()
          }
        },
        // 切换布局
        switchLayout(mode) {
          if (this.layoutMode !== mode) {
            this.layoutMode = mode
            this.restoreLayout()
          }
        },
        // 保存布局
        saveLayout() {
          const {layoutMode, nodes, layouts, updateLayout, projectInfo} = this
          const layoutNodes = nodes.map(({id, x, y}) => ({id, x, y}))
          // console.log(`saveLayout layout mode: ${layoutMode}`, layoutNodes)
          updateLayout({
            type: layoutMode,
            projectId: projectInfo.projectId,
            nodes: layoutNodes
          }).then(res => {
            if (res) {
              layouts[layoutMode].nodes = layoutNodes
            }
          })
        },
        // 恢复布局
        restoreLayout(bool) {
          const {
            config,
            layoutMode,
            layouts,
            nodes,
            pin,
            unPin,
            flags: {pinned},
            setLocked
          } = this
          
          if (
            bool ||
            (layoutMode === 'GRID' && layouts.GRID.nodes.length !== nodes.length)
          ) {
            layouts.GRID.nodes = getGridLayout(nodes, config)
            const layoutNodesMapper = {}
            console.log('layouts:', layouts)
            console.log('layoutMode:', layoutMode)
            layouts.GRID.nodes.forEach(({id, x, y}) => {
              layoutNodesMapper[id] = {x, y}
            })
            console.log(`restoreLayout ${layoutMode}:`, layoutNodesMapper)
      
            unPin()
            nodes.forEach(node => {
              if (Reflect.has(layoutNodesMapper, node.id)) {
                const {x, y} = layoutNodesMapper[node.id]
                node.x = x
                node.y = y
                if (pinned) {
                  node.fx = x
                  node.fy = y
                }
              }
            })
            setLocked(layoutMode === 'GRID')
            layoutMode === 'FORCE' ? unPin() : pin()
          }
          
        },
        // 选取类别
        selectGroups(groups) {
          // console.log('selectGroups', groups)
          this.setSelectedGroups(groups)
          this.updateNodesWithText()
          this.updateLinksWithText()
        },
        // 直接选中单个节点
        selectNode(nodeId) {
          // console.log('graph selectNode', nodeId)
          const node = this.getNodeById(nodeId)
          this.setFocus(node)
          this.setNodeFocus(node)
        },
        // 多个节点一次高亮
        highLightMultiple(nodeIds) {
          this.clearFocus()
          // console.log('highLightMultiple', nodeIds)
          const nodes = this.getNodesByIds(nodeIds)
          nodes.forEach(node => this.setNodeHighLight(node, true))
          this.updateHighLightNodes()
        },
        // 切换选中模式
        setSelectingMode(mode) {
          this.flags.selectingMode = mode
        },
        selectInSelectingMode() {
        },
        /********** 图谱操作 **********/
        // 设置高亮组
        setFocusNodes(nodeIds) {
          const {
            config: {baseRadius},
            focusNodes,
            svgElements: {focusGroup: fg},
            getNodesByIds,
            setNodeFocus
          } = this
          const targetNodes = getNodesByIds(nodeIds)
          targetNodes.forEach(node => setNodeFocus(node))
    
          fg.selectAll('circle')
            .data(focusNodes)
            .enter()
            .insert('circle')
            .attr('r', d => baseRadius + d.radius * 10 + 5)
            .attr('fill', 'none')
            .attr('id', d => `focus-node-${d.id}`)
            .attr('cx', d => d.x)
            .attr('cy', d => d.y)
        },
        // 清除高亮
        clearFocus() {
          this.svgElements.focusGroup.selectAll('circle').remove()
          this.svgElements.root.select('.menuCircle').remove()
          this.nodes.forEach(node => {
            this.setNodeHighLight(node, false)
            this.clearNodeFocus(node)
          })
        },
        // 固定节点
        pin() {
          const {
            nodes,
            flags: {pinned}
          } = this
          if (!pinned) {
            this.flags.pinned = true
            nodes.forEach(node => {
              node.fx = node.x
              node.fy = node.y
            })
          }
        },
        // 取消固定
        unPin() {
          const {
            svgElements: {simulation},
            nodes
          } = this
          this.flags.pinned = false
          nodes.forEach(node => {
            node.fx = null
            node.fy = null
          })
          simulation.alpha(1).restart()
        },
        dragMove(d) {
          d.dx += this.$d3.event.dx
          d.dy += this.$d3.event.dy
          this.$d3.select(this)
            .attr("transform", "translate(" + d.dx + "," + d.dy + ")")
        },
        addMyLinks(nodeOrId) {
          console.log('[GraphBoard]', nodeOrId)
          const {
            $d3,
            nodes,
            links,
            updateNodesWithText,
            updateLinksWithText,
            createNode,
            createLink,
            clearFocus,
            layoutMode,
            restoreLayout,
            getNodeById,
            isContains,
            projectInfo
          } = this
          const nodeId = nodeOrId.id
          const entityName = nodeOrId.name
          console.log("nodeOrID",nodeOrId)
          let isInclude = false
          // const projectId = this.projectId
          // Number(this.$route.params.projectId)
          const data = {
            "entityId": nodeId,
            "entityName": entityName,
            "fuzzyQuery": true,
            "projectId": nodeOrId.projectId
          }
          this.hasDoubleClicked.push(nodeId)
          this.entityQueryGlobal(data).then(res => {
            if (res) {
              res.nodes.forEach(node => {
                res.links.forEach(link => {
                  // console.log("请求测试：向后端请求了9841："  + JSON.stringify(link))
                  if (link.target === node.id) {
                    this.middleLinks.push(link)
                    console.log("链接测试9846415112link" + JSON.stringify(link))
                  }
                })
  
                console.log("1271双击测试sadasd：" + node.id)
  
                if (getNodeById(node.id)) {
                  getNodeById(node.id).isNew = false
                  console.log("1427")
                } else {
                  node.isNew = false
                  node.isDelete = false
                  node.opacity = false
                  nodes.push(node)
                  if (!this.selectedGroups.includes(node.group)) {
                    this.selectedGroups.push(node.group)
                  }
                  this.allNodes.push(node.id)
                }
  
              })
  
              bus.$emit("changeAllGroups", this.selectedGroups)
  
              // this.$emit('recieveGroup',this.selectedGroups)
  
              // this.links = this.middleLinks
  
              if (this.delelinks.length !== 0) {
                const _link = this.delelinks.filter(_link => _link.to === nodeId)
  
                if (_link.length !== 0) {
                  for (const prop in _link) {
                    createLink(_link[prop])
                    this.delelinks.splice(this.delelinks.indexOf(_link[prop]), 1)
                  }
                }
                this.addLoopNode(nodeId)
              }
  
              updateNodesWithText()
              updateLinksWithText()
              clearFocus()
              this.svgElements.root.select('.menuCircle').remove()
              layoutMode === 'GRID' && restoreLayout(true)
            }
          })
        // }
      },
        returnGroups() {
          return this.selectedGroups
        },
    
        addLoopNode(nodeId) {
          const {
            nodes,
            links,
            createNode,
            createLink,
          } = this
          const _linkto = this.delelinks.filter(_linkto => _linkto.from === nodeId)
    
    
          console.log("1230展开测试：" + JSON.stringify(_linkto))
    
          if (_linkto.length !== 0) {
            for (const prop in _linkto) {
              // delete nodes
              const nodeto = this.delenodes.filter(nodeto => nodeto.id === _linkto[prop].to)[0]
              if (typeof (nodeto) !== 'undefined') {
                // add nodes
                createNode(nodeto)
                this.delenodes.splice(this.delenodes.indexOf(nodeto), 1)
                // add links
                createLink(_linkto[prop])
                this.delelinks.splice(this.delelinks.indexOf(_linkto[prop]), 1)
                this.addLoopNode(_linkto[prop].to)
              }
            }
          }
        },
        //收起
        deleteMyLinks(nodeOrId) {
          // console.log('[delBoard]', nodeOrId)
          const {
            nodes,
            links,
            updateNodesWithText,
            updateLinksWithText,
            clearFocus,
            layoutMode,
            restoreLayout
          } = this
          // console.log('[delBoard]', nodes)
          const nodeId = nodeOrId.id
          const nodegroup = nodeOrId.group
          //收起的Links
          const node = nodes.filter(node => node.id === nodeId)[0]
          const _link = links.filter(_link => _link.from === nodeId)
    
          for (const prop in _link) {
            // delete links
            // links.splice(links.indexOf(_link[prop]), 1)
            this.delelinks.push(_link[prop])
          }
    
          this.deleLoopNode(nodeId)
          //console.log('[delelinks]',this.delelinks)
          updateNodesWithText()
          updateLinksWithText()
          clearFocus()
          this.svgElements.root.select('.menuCircle').remove()
          layoutMode === 'GRID' && restoreLayout(true)
        },
        deleLoopNode(nodeId) {
          const {
            nodes,
            links,
          } = this
    
          console.log("收起测试" + JSON.stringify(this.delelinks))
    
          const _linkto = links.filter(_linkto => _linkto.from === nodeId)
    
          if (_linkto.length !== 0) {
            for (const prop in _linkto) {
              // delete links
              links.splice(links.indexOf(_linkto[prop]), 1)
              this.delelinks.push(_linkto[prop])
              // delete nodes
              const nodeto = nodes.filter(nodeto => nodeto.id === _linkto[prop].to)[0]
    
              if (typeof (nodeto) !== 'undefined') {
                nodes.splice(nodes.indexOf(nodeto), 1)
                this.delenodes.push(nodeto)
                this.deleLoopNode(_linkto[prop].to)
              }
            }
          }
        },
        // 点击节点
        clickNode(e) {
          console.log("输出鼠标按键编号:" + e.which);
    
          // console.log("1298点击测试" + JSON.stringify(e))
          const {
            config: {baseRadius},
            nodes,
            flags: {enableFocus},
            svgElements: {root, focusGroup: fg},
            getNodeById,
            getProjectInfoAct
          } = this
          this.clearFocus()
          const id = Number(e.target.attributes['data-id'].value)
    
          const node = getNodeById(id)
          
          this.projectId = node.projectId
    
          console.log("点击了节点561651：" + JSON.stringify(node))
          this.selectedItem.type == 'node'
          this.selectedItem.item == node
          console.log("获取项目信息：" + this.projectId)
          node.textSize = parseInt(node.textSize)
          // console.log("点击测试85556:"+JSON.stringify(node))
          // node.group = JSON.parse(node.group)
          // console.log("点击测试85557："+JSON.stringify(node))
          if (node.isDelete)
            return
    
          //const originFocus = fg.selectAll('circle')
          //console.log(`click node: id=${id}, `, root)
    
    
          if (this.flags.selectingMode) {
            this.flags.selectingMode = false
            console.log("数据测试111：执行了节点点击方法")
            this.$emit('editor-action', 'catchNode', node,)
          } else {
            this.setNodeFocus(node)
    
            // //wx
            // this.toggleCircle_wx(this.svgElements.svg, e)
            this.$emit('editor-action', 'selectNode', {...node})
            this.$emit('msg-action', 'setSituationid', {...node})
            // console.log(`click node t2: id=${node.id}, `, node)
            //调用收起、展开功能
            // this.toggleCircle(root, node)
    
            //圆环菜单构建方法
            // this.toggleCircle_wx(root, node)
    
          }
        },
        // 点击关系
        clickLink(e) {
          if (this.flags.selectingMode) return
          const id = Number(e.target.attributes['data-id'].value)
          const link = this.getLinkById(id)
          // console.log(`click link: id=${id}, `, link)
    
          this.clearFocus()
          this.$emit('editor-action', 'selectLink', {...link})
        },
        clickView() {
          if (this.flags.selectingMode) return
          this.clearFocus()
          this.$emit('editor-action', 'selectNone')
        },
    
        // 聚焦(高亮显示)
        focus(e) {
          const {
            getNodeById,
            setFocus,
            flags: {enableFocus},
            root,
          } = this
          if (!enableFocus) return
          const id = Number(e.target.attributes['data-id'].value)
          const targetNode = getNodeById(id)
    
          if (targetNode.haveCircle)
            this.toggleCircle_wx(root, targetNode)
    
          //console.log(`focus: id=${id}, `, targetNode)
          if (!targetNode || targetNode.isDelete) return
    
          setFocus(targetNode)
        },
        // 取消聚焦
        unfocus(e) {
    
          // console.log("焦点移除" + JSON.stringify(e))
          const {
            flags: {enableFocus},
            _unfocus
          } = this
          if (!enableFocus) return
    
          const id = Number(e.target.attributes['data-id'].value)
          _unfocus(id)
        },
        _unfocus(id) {
          const {
            svgElements: {focusGroup: fg},
            getNodeById,
            setNodeHighLight
          } = this
          const targetNode = getNodeById(id)
          setNodeHighLight(targetNode, false)
          const focusNode = fg.select(`#focus-node-${id}`)
          if (!focusNode.empty()) {
            if (targetNode && targetNode.focus) return
    
            focusNode.remove()
    
          }
        },
        /********** 力导图绑定事件 **********/
        // 拖曳设置
        setDrag(simulation) {
    
          const {setEnableFocus, flags, nodes} = this
    
          const start = (e, d) => {
            if (!e.active) simulation.alphaTarget(0.3).restart()
            setEnableFocus(false)
            if (flags.locked) {
              const group = d.group
              nodes
                .filter(node => node.group === group)
                .forEach(node => {
                  node.fx = d.x
                })
    
            } else {
              d.fx = d.x
              d.fy = d.y
            }
          }
    
          const drag = (e, d) => {
            if (flags.locked) {
              const group = d.group
              nodes
                .filter(node => node.group === group)
                .forEach(node => {
                  node.fx = e.x
                })
            } else {
              d.fx = e.x
              d.fy = e.y
            }
          }
    
          const end = (e, d) => {
            setEnableFocus(true)
            if (flags.locked) return
            if (!e.active) simulation.alphaTarget(0)
            d.x = d.fx
            d.y = d.fy
            if (!flags.pinned) {
              d.fx = null
              d.fy = null
            }
          }
    
          const boundDrag = this.$d3
            .drag()
            .on('start', start)
            .on('drag', drag)
            .on('end', end)
          this.svgElements.boundDrag = boundDrag
    
          return boundDrag
        },
        // 缩放&平移设置
        setZoom(root) {
          const boundZoom = this.$d3.zoom().on('zoom', e => {
            root.attr('transform', e.transform)
          })
          this.svgElements.boundZoom = boundZoom
          return boundZoom
        },
        /********** 数据属性操作 **********/
        // 根据 id 查找节点
        getNodeById(id) {
          return this.nodes.filter(node => node.id === id)[0]
        },
        getNode(nodeOrId) {
          return typeof nodeOrId === 'object'
            ? nodeOrId
            : this.getNodeById(nodeOrId)
        },
        // 根据 id 查找关系
        getLinkById(id) {
          return this.links.filter(link => link.id === id)[0]
        },
        // 设置选中组别
        setSelectedGroups(groups) {
          // console.log("组别测试sadas" + JSON.stringify(this.selectedGroups))
          this.selectedGroups = groups
          // console.log("组别测试sadas" + JSON.stringify(this.selectedGroups))
          this.updateAllOpacity()
        },
        // updateAllOpacity() {
        //   const {selectedGroups: groups, nodes, links} = this
        //   nodes.forEach(node => {
        //     // node.color = node.color ? "#" + node.color.slice(1, node.color.length) + "33" : this.svgElements.scale(node.group)+"33"
        //   })
        //   links.forEach(link => {
        //     link.opacity = link.source.opacity || link.target.opacity
        //   })
        // },
    
        updateAllOpacity() {
          const {selectedGroups: groups, nodes, links} = this
          if (nodes) {
            nodes.forEach(node => {
              node.opacity = !groups.includes(node.group)
            })
            links.forEach(link => {
              link.opacity = link.source.opacity || link.target.opacity
            })
          }
        },
    
        // 设置节点高亮标志
        setNodeHighLight(nodeOrId, bool = false) {
          const node = this.getNode(nodeOrId)
          node.highLight = bool
        },
        setNodeFocus(nodeOrId) {
          const {
            nodes,
            flags: {singleFocus},
            _unfocus,
            getNode
          } = this
          const node = getNode(nodeOrId)
    
          if (singleFocus) {
            nodes
              .filter(n => n !== node)
              .forEach(node => {
                if (node.focus) {
                  node.focus = false
                  _unfocus(node.id)
                }
              })
          }
          node.focus = true
        },
        clearNodeFocus(nodeOrId) {
          const node = this.getNode(nodeOrId)
          node.focus = false
        },
        getNodesByIds(ids) {
          return this.nodes.filter(node => ids.includes(node.id))
        },
        /********** 图谱标志 **********/
        setEnableFocus(bool = true) {
          this.flags.enableFocus = bool
        },
        setLocked(bool = false) {
          this.flags.locked = bool
        },
        /********** 图谱标志 **********/
        exportPng() {
          const projectName = this.projectInfo.name
          const svg = this.svgElements.svg
          this.saveAsPng({projectName, svg})
    
        },
        exportXml() {
          const {projectId, name} = this.projectInfo
          console.log("信息获取789432：" + projectId + "  " + name)
          this.saveAsXml({projectId, name})
        },
       
        doubleClick(e) {
          const {
            getNodeById,
            addMyLinks
          } = this
    
          this.clearFocus()
          const id = Number(e.target.attributes['data-id'].value)
          const node = getNodeById(id)
          
          if (!node.isDelete) {
            addMyLinks(node)
          }
          console.log("1843执行了双击" + node.id)
        },
    
        //wx2.13
        setCirileMenu(root) {
          const menuGroup = root
            .append('g')
            .attr('class', 'circle-menu')
            .attr("")
          this.svgElements.menuGroup = menuGroup
        },
    
        // searchAddOne(data) {
          
        //   this.entityQueryGlobal(data).then((res) => {
        //       console.log("searchAddOne搜索结果"+JSON.stringify(res))
        //       this.graphData = res
        //       const nodeSearch = this.$refs.queryBoard
        //       nodeSearch.mountGraphData(this.graphData,this.projectInfo) 
        //     })
          
        // },
    
        isContains(returnNode) {
          if (this.nodes.contain(returnNode))
            return true;
          else
            return false;
        },
    
    
      },
      async mounted() {
      
      // const projectId = 0
      // const projectId = Number(this.$route.params.projectId)
      // const projectInfo = await this.getProjectInfoAct(projectId)
      // if (!projectInfo) {
      //   // warning
      //   return
      // }
      // this.projectInfo = projectInfo
  
      //初始化图谱数据
      const graphData = await this.getProjectGraphDataAct(projectId)
  
      // const graphData = deepCopy(_graphData)
      if (!graphData) {
        // warning
        return
      }
      this.graphData = graphData
      console.log("初始化图谱数据结果09123012："+JSON.stringify(this.graphData))
  
      const nodeSearch = this.$refs.queryBoard
      nodeSearch.mountGraphData(this.graphData, this.projectInfo)
  
      console.log('projectId:', projectId)
      console.log('projectInfo:', projectInfo)
      console.log('graphData:', graphData)
    }
    }
    </script>
    
    <style scoped>
    #graph {
      width: 100%;
      height: 100%;
    }
    </style>
    